// Copyright  2004-2008 Backplane Ltd.
//
// This file is part of Ubiquity formsPlayer
//
// Ubiquity formsPlayer is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the
// Free Software Foundation; either version 3 of the License, or (at your
// option) any later version.
//
// Ubiquity formsPlayer is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
// more details.
//
// You should have received a copy of the GNU General Public License
// along with Ubiquity formsPlayer If not, see <http://www.gnu.org/licenses/>.
//	
//
//   Purpose:  Implementation of CFactory.
//   $Id$



// Factory.cpp : Implementation of CXFormsApp and DLL registration.

#include "stdafx.h"
#include <new>
#include "XForms.h"
#include "Factory.h"
#include "XFormsElement.h"
#include "ButtonUI.h"
#include "FormControlInputUI.h"
//#include "InputController.h"
#include "OutputUI.h"
#include "RangeUI.h"
#include "RepeatUI.h"
#include "SecretUI.h"
#include "SingleNodeBindingUI.h"
#include "NodesetBindingUI.h"
#include "parseSubmission.h"

#include "SubmitUI.h"
#include "SubmissionUI.h"
#include "SwitchUI.h"
#include "TextAreaUI.h"
#include "ModelUI.h"
#include "SelectUI.h"
#include "GroupUI.h"
#include "uploadUI.h"
#include "HintUI.h"
#include "HelpUI.h"
#include "XFormsElementAction.h"
#include "XFormsElementDispatch.h"
#include "XFormsElementDelete.h"
#include "XFormsElementInsert.h"
#include "XFormsElementLoad.h"
#include "XFormsElementRebuild.h"
#include "XFormsElementRecalculate.h"
#include "XFormsElementRevalidate.h"
#include "XFormsElementRefresh.h"
#include "XFormsElementSetfocus.h"
#include "XFormsElementsetValue.h"
#include "XFormsElementSend.h"
#include "XFormsElementReset.h"
#include "XFormsElementMessage.h"
#include "XFormsElementToggle.h"
#include "XFormsElementSetIndex.h"
#include "XFormsElementDestroy.h"
#include "XFormsElementDuplicate.h"
#include "XFormsElementClose.h"
#include "ItemsetUI.h"
#include "PEValueElement.h"
#include "XFormsMTSElementWithXBL.h"

#include "CreateReferencedInstance.h"
#include "CaseUI.h"
//#import <xforms/extension/extension.dll> named_guids


// #include "ElementWithValue.h"

#include "XFormsElementItem.h"

//#include "DynamicContentView.h"
//#include "DynamicContentController.h"
#include "FP_Definitions.h"
#include "XFormsApp.h"
#include "eventmsg.h"
extern CXFormsApp theApp;

/////////////////////////////////////////////////////////////////////////////
//

STDMETHODIMP CFactory::InterfaceSupportsErrorInfo(REFIID riid)
{
	static const IID* arr[] =
	{
		&IID_IFactory,
	};

	for (int i=0;i<sizeof(arr)/sizeof(arr[0]);i++)
	{
		if (::InlineIsEqualGUID(*arr[i],riid))
			return S_OK;
	}
	return S_FALSE;
}

CFactory::~CFactory()
{
}
/*
//<summary>creates an instance of the Extension object, used in the object creation map. </summary>
HRESULT __stdcall CreateExtension(IUnknown ** ppResult)
{
	CComPtr<extensionLib::IExtension> pExt;
	HRESULT hr = pExt.CoCreateInstance(extensionLib::CLSID_Extension);
	pExt->QueryInterface(IID_IUnknown,(void**)ppResult);

	return  hr;
}
*/

/*
 * Find the correct object for the tag
 */
CFactory::CFactory()
	:m_pForm(0)
	,m_lFormId(0)
	,m_bRequiresSave(FALSE)
{
	if(!sm_hObjectCreationMapMutex)
		sm_hObjectCreationMapMutex = CreateMutex(0, FALSE, _T("Local\\FactoryObjectCreationMapMutex"));

	if(!sm_hActionObjectCreationMapMutex)
		sm_hActionObjectCreationMapMutex = CreateMutex(0, FALSE, _T("Local\\FactoryActionObjectCreationMapMutex"));

	if(!sm_hDebugAgentFactoryMutex)
		sm_hDebugAgentFactoryMutex = CreateMutex(0, FALSE, _T("Local\\DebugAgentFactoryMutex"));

	if(m_ObjectCreationMap.empty())
	{
//No refusals.  Child elements optionally handle themselves
		RegisterCreationFunction(g_lpwszTagModel,CreateReferencedInstance<CXFormsElementModel>,NONE);
		RegisterCreationFunction(g_lpwszTagSwitch,CreateReferencedInstance<CXFormsElementSwitch>,NONE);

//Handled by XBL
		RegisterCreationFunction(g_lpwszTagTrigger,CreateReferencedInstance<CXFormsElementButton>,NONE);
		RegisterCreationFunction(g_lpwszTagSubmit,CreateReferencedInstance<CXFormsElementSubmit>,NONE);
		RegisterCreationFunction(g_lpwszTagOutput,CreateReferencedInstance<CXFormsElementOutput>,NONE);
		RegisterCreationFunction(g_lpwszTagGroup,CreateReferencedInstance<CXFormsElementGroup>,NONE);

		RegisterCreationFunction(g_lpwszTagPEValue,CreateReferencedInstance<CPEValueElement>,NONE);
		RegisterCreationFunction(g_lpwszTagLabel,CreateReferencedInstance<CXFormsMTSElementWithXBL>,NONE);
//Refuse - Working like nested literal.
		RegisterCreationFunction(g_lpwszTagRepeat,CreateReferencedInstance<CXFormsElementRepeat>,REFUSE);
		RegisterCreationFunction(g_lpwszTagCase,CreateReferencedInstance<CXFormsElementCase>,REFUSE);
//Controls in viewlink.  Action child elements control themselves, but other elements are handled within parse of containing element.
		RegisterCreationFunction(g_lpwszTagInput,CreateReferencedInstance<CXFormsElementInput>,NONE);
		RegisterCreationFunction(g_lpwszTagRange,CreateReferencedInstance<CXFormsElementRange>,NONE);
		RegisterCreationFunction(g_lpwszTagSecret,CreateReferencedInstance<CXFormsElementSecret>,NONE);
		RegisterCreationFunction(g_lpwszTagSubmission,CreateReferencedInstance<CXFormsElementSubmission>,ACTIONS);
		RegisterCreationFunction(g_lpwszTagTextArea,CreateReferencedInstance<CXFormsElementTextArea>,NONE);
		RegisterCreationFunction(g_lpwszTagUpload,CreateReferencedInstance<CXFormsElementUpload>,ACTIONS);
		RegisterCreationFunction(g_lpwszTagItem,CreateReferencedInstance<CXFormsElementItem>,ACTIONS);
		RegisterCreationFunction(g_lpwszTagItemset,CreateReferencedInstance<CXFormsElementItemset>,ACTIONS);
//Special controls, 
		RegisterCreationFunction(g_lpwszTagSelectMany,CreateReferencedInstance<CXFormsElementSelectMany>,SELECT_CHILD);
		RegisterCreationFunction(g_lpwszTagSelectOne,CreateReferencedInstance<CXFormsElementSelectOne>,SELECT_CHILD);


//Actions
		RegisterCreationFunction(g_lpwszTagHint,CreateReferencedInstance<CXFormsElementHint>,NONE);
		RegisterCreationFunction(g_lpwszTagHelp,CreateReferencedInstance<CXFormsElementHelp>,NONE);
		RegisterCreationFunction(g_lpwszTagAction,CreateReferencedInstance<CXFormsElementAction>,NONE);
		RegisterCreationFunction(g_lpwszTagDelete,CreateReferencedInstance<CXFormsElementDelete>,NONE);
		RegisterCreationFunction(g_lpwszTagDispatch,CreateReferencedInstance<CXFormsElementDispatch>,NONE);
		RegisterCreationFunction(g_lpwszTagInsert,CreateReferencedInstance<CXFormsElementInsert>,NONE);
		RegisterCreationFunction(g_lpwszTagLoad,CreateReferencedInstance<CXFormsElementLoad>,NONE);
		RegisterCreationFunction(g_lpwszTagMessage,CreateReferencedInstance<CXFormsElementMessage>,REFUSE);
		RegisterCreationFunction(g_lpwszTagRebuild,CreateReferencedInstance<CXFormsElementRebuild>,NONE);
		RegisterCreationFunction(g_lpwszTagRecalculate,CreateReferencedInstance<CXFormsElementRecalculate>,NONE);
		RegisterCreationFunction(g_lpwszTagRefresh,CreateReferencedInstance<CXFormsElementRefresh>,NONE);
		RegisterCreationFunction(g_lpwszTagRevalidate,CreateReferencedInstance<CXFormsElementRevalidate>,NONE);
		RegisterCreationFunction(g_lpwszTagReset,CreateReferencedInstance<CXFormsElementReset>,NONE);
		RegisterCreationFunction(g_lpwszTagSend,CreateReferencedInstance<CXFormsElementSend>,NONE);
		RegisterCreationFunction(g_lpwszTagSetFocus,CreateReferencedInstance<CXFormsElementSetfocus>,NONE);
		RegisterCreationFunction(g_lpwszTagSetValue,CreateReferencedInstance<CXFormsElementSetValue>,REFUSE);
		RegisterCreationFunction(g_lpwszTagToggle,CreateReferencedInstance<CXFormsElementToggle>,NONE);
		RegisterCreationFunction(g_lpwszTagSetIndex,CreateReferencedInstance<CXFormsElementSetIndex>,NONE);
		RegisterCreationFunction(g_lpwszTagClose, CreateReferencedInstance<CXFormsElementClose>,NONE);

		RegisterCreationFunction(L"destroy",CreateReferencedInstance<CXFormsElementDestroy>,NONE);
		RegisterCreationFunction(L"duplicate",CreateReferencedInstance<CXFormsElementDuplicate>,NONE);
//		RegisterCreationFunction(L"extension",&CreateExtension,NONE);

//Action functions are also separately registered, so that they are not refused by elements with ACTION in their
//		third RegisterCreationFunction parameter.
//TODO: This could be better organised, as could its usage in findBehaviour.  
		RegisterActionFunction(g_lpwszTagClose, CreateReferencedInstance<CXFormsElementClose>);
		RegisterActionFunction(g_lpwszTagAction,CreateReferencedInstance<CXFormsElementAction>);
		RegisterActionFunction(g_lpwszTagDelete,CreateReferencedInstance<CXFormsElementDelete>);
		RegisterActionFunction(g_lpwszTagDispatch,CreateReferencedInstance<CXFormsElementDispatch>);
		RegisterActionFunction(g_lpwszTagInsert,CreateReferencedInstance<CXFormsElementInsert>);
		RegisterActionFunction(g_lpwszTagLoad,CreateReferencedInstance<CXFormsElementLoad>);
		RegisterActionFunction(g_lpwszTagMessage,CreateReferencedInstance<CXFormsElementMessage>);
		RegisterActionFunction(g_lpwszTagHelp,CreateReferencedInstance<CXFormsElementHelp>);
		RegisterActionFunction(g_lpwszTagRebuild,CreateReferencedInstance<CXFormsElementRebuild>);
		RegisterActionFunction(g_lpwszTagRecalculate,CreateReferencedInstance<CXFormsElementRecalculate>);
		RegisterActionFunction(g_lpwszTagRefresh,CreateReferencedInstance<CXFormsElementRefresh>);
		RegisterActionFunction(g_lpwszTagRevalidate,CreateReferencedInstance<CXFormsElementRevalidate>);
		RegisterActionFunction(g_lpwszTagReset,CreateReferencedInstance<CXFormsElementReset>);
		RegisterActionFunction(g_lpwszTagSend,CreateReferencedInstance<CXFormsElementSend>);
		RegisterActionFunction(g_lpwszTagSetFocus,CreateReferencedInstance<CXFormsElementSetfocus>);
		RegisterActionFunction(g_lpwszTagSetValue,CreateReferencedInstance<CXFormsElementSetValue>);
		RegisterActionFunction(g_lpwszTagToggle,CreateReferencedInstance<CXFormsElementToggle>);
		RegisterActionFunction(g_lpwszTagSetIndex,CreateReferencedInstance<CXFormsElementSetIndex>);
		RegisterActionFunction(L"destroy",CreateReferencedInstance<CXFormsElementDestroy>);
		RegisterActionFunction(L"duplicate",CreateReferencedInstance<CXFormsElementDuplicate>);

	//	RegisterActionFunction(L"extension",CreateExtension);
		RegisterActionFunction(g_lpwszTagHint,CreateReferencedInstance<CXFormsElementHint>);
	}
}

HRESULT CFactory::ResolveForm(IHTMLElement *pEl)
{
	HRESULT hr = E_INVALIDARG;
	if(m_lFormId)
		//Externally specified <param> form id,
		//Get The Form	
		hr = theApp.FormsManager().GetForm(m_lFormId,&m_pForm);
	else if(pEl)
	{
		CComPtr<IDispatch> pDisp;
		hr = pEl->get_document(&pDisp);
		CComQIPtr<IHTMLDocument4> pDoc4 = pDisp;
		CComBSTR bsMedia;
		if(pDoc4)
			pDoc4->get_media(&bsMedia);
		if(bsMedia == L"print")
			hr =  E_FAIL;
		else 
		{
			CComQIPtr<IHTMLDocument2> pDoc2 = pDisp;
			if(pDoc2) {
				hr = theApp.FormsManager().GetForm(pDoc2, &m_pForm);
				if(m_pForm)
				{
					m_lFormId = reinterpret_cast<long>(m_pForm);
					HRESULT _hr = m_pForm->put_Factory(this);
				}
				else
					hr = E_FAIL;
			}
		}
	}
	return hr;
}

STDMETHODIMP CFactory::FindBehavior(BSTR bstrBehavior, BSTR bstrBehaviorUrl,
		IElementBehaviorSite* pSite, IElementBehavior** ppBehavior)
{
	
	HRESULT hr = S_OK;

	try {
		CComPtr<IHTMLElement> pEl;
		hr = pSite->GetElement(&pEl);

		if(!m_pForm)
		{
			//if this is the first call for this factory, 
			//Get the form to which this factory is attached.
			ResolveForm(pEl);
		}

		if(SUCCEEDED(hr) && pSite) 
		{
			//Temp - only create label/help/alert if the parent supports live children.
			//TODO: I think this is unneccessary, and will probably be handled by the newer
			//	findbehaviour refusal/acceptance business.  Fixing this will lead to improved
			//	load times.
			//	Even if it is needed, I think it should probably go into ShouldThisFindBehaviourRequestBeRefused

			if(g_lpwszTagLabel == bstrBehavior  || g_lpwszTagAlert == bstrBehavior)
			{
				CComPtr<IHTMLElement>pParentEl;
				pEl->get_parentElement(&pParentEl);
				CComVariant val;
				HRESULT _hr = pParentEl->getAttribute(L"liveChildren",1,&val);	
				if(_hr != S_OK || val.vt != VT_BSTR || wcscmp(val.bstrVal,L"yes") != 0)
					hr = E_FAIL;
				else
					hr = _hr;
			}
		}
//debug code - step in here to get a look at the element making the request
#ifdef _DEBUG
		if(false)
		{
			CComPtr<IHTMLElement>pParentEl;
			pEl->get_parentElement(&pParentEl);
			CComBSTR s;
			pParentEl->get_outerHTML(&s);
			::MessageBoxW(0,s,0,0);
		}
#endif

		if(SUCCEEDED(hr))
		{
			bool bRefuse = ShouldThisFindBehaviourRequestBeRefused(pSite,bstrBehavior);

			if(bRefuse)
			{
				hr = E_FAIL;
				*ppBehavior = 0;
				CComBSTR sTag;
				pEl->get_tagName(&sTag);
				if(sTag == "repeat")
				{
					CComVariant v;
					pEl->getAttribute(L"id",2,&v);
					if(v.vt == VT_BSTR)
					{
						m_pForm->AddPendingRepeat(v.bstrVal);
					}
				}
			}
			else
			{
				ObjectCreationFunctionPtr fn = 0;

				WaitForSingleObject(sm_hObjectCreationMapMutex, INFINITE);

				try
				{
					CMapCComBSTRToObjectCreationData::iterator i;
					//Get the creation function out of the creation map.
					if(bstrBehavior)
						i = m_ObjectCreationMap.find(bstrBehavior);
					else if(bstrBehaviorUrl)
						i = m_ObjectCreationMap.find(bstrBehaviorUrl);

					if(i != m_ObjectCreationMap.end())
					{
						fn = i->second.first;
						if(i->second.second != NONE)
							SetFindBehaviourResponseWithin(pEl,i->second.second);
					}
				}
				catch(...)
				{
				}

				ReleaseMutex(sm_hObjectCreationMapMutex);

				//if a function has been found, execute it to get the behaviour.
				if(fn)
				{
					
					IUnknown * pUnk = NULL;
					hr = fn(&pUnk);

					CComQIPtr<IObjectWithForm> pOurBehaviour(pUnk);
					if(pOurBehaviour)
					{
						pOurBehaviour->put_formKey(m_lFormId);
					}


					hr = pUnk->QueryInterface(IID_IElementBehavior, (void**) ppBehavior);
					pUnk->Release();
				}
				else
				{
					//::MessageBoxW(0,L"no fn in findbehaviour",bstrBehavior,0);
				}
			}
		}
	}
	catch(...) {
		AtlTrace("exception in findbehaviour");
		ASSERT(0);
		//::MessageBoxW(0,L"exception in findbehaviour",bstrBehavior,0);
		hr = E_FAIL;
	}
	return hr;
}
/*
 * Need to add all the elements that are allowed at the top level.
 *
 * It is also possible to put attributes onto ordinary HTML elements.
 *			****This is no longer the case****
 */


STDMETHODIMP CFactory::Create(IElementNamespace* pNamespace)
{
	try {

		/*
		* These are top level elements. All others are handled within the handling for these
		*
		* If an element simply contains others, then use:
		*
		*	AddTag(x, 0);
		*
		* An example would be model:
		*
		*	<xforms:model>
		*		<xforms:instance> ... </xforms:instance>
		*	</xforms:model>
		*
		* If the content of an element is going to be used by the element itself then use:
		*
		*	AddTag(x, ELEMENTDESCRIPTORFLAGS_LITERAL);
		*
		* An example would be instance, which may contain inline XML, or load some XML from a URL:
		*
		*	<xforms:instance>
		*		<x>
		*			<y />
		*		</x>
		*	</xforms:instance>
		*
		* Finally, if the content is a set of nested XForms elements, then use:
		*
		*	AddTag(x, ELEMENTDESCRIPTORFLAGS_NESTED_LITERAL);
		*
		* This is because if only ELEMENTDESCRIPTORFLAGS_LITERAL was used, IE wouldn't know how to handle
		* this:
		*
		*	<xforms:group>
		*		<xforms:group>
		*			<xforms:input ... />
		*		</xforms:group>
		*	</xforms:group>
		*
		* Of course, it should be able to work it out, but it doesn't, and simply interprets combines everything
		* up to the next xforms:group element as a block of literal text:
		*
		*	<xforms:group>
		*		<xforms:group>				| Literal
		*			<xforms:input ... />	| text
		*	</xforms:group>
		*	</xforms:group>					| Trailing closing tag
		*
		* Using ELEMENTDESCRIPTORFLAGS_NESTED_LITERAL tells IE to watch for the opening and closing elements,
		pNamespace->AddTag(::SysAllocString(g_lpwszTagInstance), ELEMENTDESCRIPTORFLAGS_NESTED_LITERAL);
		* even though it will still interpret the contents as literals (i.e., not well-formed XML).
		*/
		pNamespace->AddTag(g_lpwszTagExtension, ELEMENTDESCRIPTORFLAGS_NESTED_LITERAL);
		pNamespace->AddTag(g_lpwszDestroy,0);
		pNamespace->AddTag(g_lpwszDuplicate,0);

		pNamespace->AddTag(g_lpwszTagTrigger, 0);
		pNamespace->AddTag(g_lpwszTagGroup,0);// ELEMENTDESCRIPTORFLAGS_NESTED_LITERAL);
		pNamespace->AddTag(g_lpwszTagInput, 0);
		pNamespace->AddTag(g_lpwszTagModel, 0);
		pNamespace->AddTag(g_lpwszTagInstance, ELEMENTDESCRIPTORFLAGS_NESTED_LITERAL);
		pNamespace->AddTag(g_lpwszTagSchema, ELEMENTDESCRIPTORFLAGS_LITERAL);
		pNamespace->AddTag(g_lpwszTagOutput, 0);
		pNamespace->AddTag(g_lpwszTagRange, 0);
		pNamespace->AddTag(g_lpwszTagRepeat,0);
		pNamespace->AddTag(g_lpwszTagSecret, 0);
		pNamespace->AddTag(g_lpwszTagSelectMany, 0);
		pNamespace->AddTag(g_lpwszTagSelectOne, 0);
		pNamespace->AddTag(g_lpwszTagSubmit, 0);
		pNamespace->AddTag(g_lpwszTagSubmission, 0);
		pNamespace->AddTag(g_lpwszTagSwitch, 0);
		pNamespace->AddTag(g_lpwszTagCase, 0);// ELEMENTDESCRIPTORFLAGS_NESTED_LITERAL);
		pNamespace->AddTag(g_lpwszTagTextArea, 0);
		pNamespace->AddTag(g_lpwszTagUpload, 0);
		pNamespace->AddTag(g_lpwszTagItem, 0);
		pNamespace->AddTag(g_lpwszTagItemset, 0);
		//Action tags.
		pNamespace->AddTag(g_lpwszTagAction,0);
		pNamespace->AddTag(g_lpwszTagDelete,0);
		pNamespace->AddTag(g_lpwszTagDispatch,0);
		pNamespace->AddTag(g_lpwszTagInsert,0);
		pNamespace->AddTag(g_lpwszTagLoad,0);
		pNamespace->AddTag(g_lpwszTagMessage,0);
		pNamespace->AddTag(g_lpwszTagRebuild,0);
		pNamespace->AddTag(g_lpwszTagRecalculate,0);
		pNamespace->AddTag(g_lpwszTagRefresh,0);
		pNamespace->AddTag(g_lpwszTagRevalidate,0);
		pNamespace->AddTag(g_lpwszTagReset,0);
		pNamespace->AddTag(g_lpwszTagSend,0);
		pNamespace->AddTag(g_lpwszTagSetFocus,0);
		pNamespace->AddTag(g_lpwszTagSetValue,0);
		pNamespace->AddTag(g_lpwszTagToggle,0);
		pNamespace->AddTag(g_lpwszTagSetIndex,0);
		pNamespace->AddTag(g_lpwszTagHint,0);
		pNamespace->AddTag(g_lpwszTagHelp,0);
		pNamespace->AddTag(g_lpwszTagClose,0);
		// Pseudo Element
		pNamespace->AddTag(g_lpwszTagPEValue, 0);
		pNamespace->AddTag(g_lpwszTagLabel, 0);

/*
 * COMMENTED OUT BY PHIL.BOOTH, 28-NOV-2005 IN CASE OF CONFLICT WITH RDM CORP FORMS.
 *
		sTag = ::SysAllocString(g_lpwszTagLabel);
		pNamespace->AddTag(sTag, ELEMENTDESCRIPTORFLAGS_LITERAL);
		::SysFreeString(sTag);
 */
	}
	catch(std::bad_alloc) {
		if(SUCCEEDED(theApp.FormsManager().RegisterEventLog()))
			theApp.FormsManager().WriteEvent(EVENTLOG_ERROR_TYPE, MSG_MEMEX);
		ASSERT(0);
	}
	catch(...) {
		if(SUCCEEDED(theApp.FormsManager().RegisterEventLog()))
			theApp.FormsManager().WriteEvent(EVENTLOG_ERROR_TYPE, MSG_TOPEX);
		ASSERT(0);
	}

	return S_OK;
}

STDMETHODIMP CFactory::Resolve(BSTR /*bstrNamespace*/, BSTR /*bstrTagName*/, BSTR/* bstrAttrs*/,
		IElementNamespace* /*pNamespace*/)
{
	return S_OK;
}

HRESULT CFactory::FinalConstruct()
{
	return S_OK;
}

void CFactory::FinalRelease(void)
{
	WaitForSingleObject(sm_hDebugAgentFactoryMutex, INFINITE);

	try
	{
		sm_pDebugAgentFactory.Release();
	}
	catch(...)
	{
	}

	ReleaseMutex(sm_hDebugAgentFactoryMutex);
}

STDMETHODIMP CFactory::addEventListener(BSTR type, IEventListener * listener, BOOL useCapture)
{
	HRESULT hr = E_NOTIMPL;
	CComQIPtr<IEventTarget> pTarget(GetControllingUnknown());
	if(pTarget)
		hr = pTarget-> addEventListener(type,listener,useCapture);
	return hr;
}
STDMETHODIMP CFactory::removeEventListener(BSTR type, IEventListener * listener, BOOL useCapture)
{
	HRESULT hr = E_NOTIMPL;
	CComQIPtr<IEventTarget> pTarget(GetControllingUnknown());
	if(pTarget)
		hr = pTarget->removeEventListener(type,listener,useCapture);
	return hr;
}
STDMETHODIMP CFactory::dispatchEvent(IDOMEvent * evt,BOOL * pbCancelled)
{
	HRESULT hr = E_NOTIMPL;
	CComQIPtr<IEventTarget> pTarget(GetControllingUnknown());
	if(pTarget)
	{
		hr = pTarget->dispatchEvent(evt,pbCancelled);
	}
	return hr;
}



CMapCComBSTRToObjectCreationData CFactory::m_ObjectCreationMap;
HANDLE CFactory::sm_hObjectCreationMapMutex = 0;

CMapCComBSTRToObjectCreationFunction CFactory::m_ActionObjectCreationMap;
HANDLE CFactory::sm_hActionObjectCreationMapMutex = 0;

CComPtr<IClassFactory> CFactory::sm_pDebugAgentFactory;
HANDLE CFactory::sm_hDebugAgentFactoryMutex = 0;

void CFactory::RegisterCreationFunction(const wchar_t * const sName, ObjectCreationFunctionPtr fn,FindBehaviourPermission p)
{
	WaitForSingleObject(sm_hObjectCreationMapMutex, INFINITE);

	try
	{
		m_ObjectCreationMap.insert(CPairCComBSTRToObjectCreationData(sName,CPairObjectCreationData(fn,p)));
	}
	catch(...)
	{
	}

	ReleaseMutex(sm_hObjectCreationMapMutex);
}

void CFactory::RegisterActionFunction(const wchar_t * const sName, ObjectCreationFunctionPtr fn)
{
	WaitForSingleObject(sm_hActionObjectCreationMapMutex, INFINITE);

	try
	{
		m_ActionObjectCreationMap.insert(CPairCComBSTRToObjectCreationFunction(sName,fn));
	}
	catch(...)
	{
	}

	ReleaseMutex(sm_hActionObjectCreationMapMutex);
}

inline HRESULT CFactory::CreateDebugAgentFactory(void)
{
	HRESULT hr = S_FALSE;

	WaitForSingleObject(sm_hDebugAgentFactoryMutex, INFINITE);

	try
	{
		if(!sm_pDebugAgentFactory)
			hr = ::CoGetClassObject(CLSID_XFormsDebugAgent, CLSCTX_ALL, 0, IID_IClassFactory, reinterpret_cast<void **>(&sm_pDebugAgentFactory));
	}
	catch(...)
	{
	}

	ReleaseMutex(sm_hDebugAgentFactoryMutex);

	return hr;
}

/*
STDMETHODIMP CFactory::GetConfigHandler(IConfigHandler **ppConfigHandler)
{
	AFX_MANAGE_STATE(AfxGetStaticModuleState());

	HRESULT hr = E_FAIL;

	try {
		if(ppConfigHandler) {
			*ppConfigHandler = theApp.FormsManager().ConfigHandler();
			(*ppConfigHandler)->AddRef();
			hr = S_OK;
		} else {
			hr = FP_E_BADARG;
			SetupErrorInfo(hr, L"CFactory::GetConfigHandler");
		}
	}
	catch(std::bad_alloc) {
		if(SUCCEEDED(theApp.FormsManager().RegisterEventLog()))
			theApp.FormsManager().WriteEvent(EVENTLOG_ERROR_TYPE, MSG_MEMEX);
		ASSERT(0);
	}
	catch(...) {
		if(SUCCEEDED(theApp.FormsManager().RegisterEventLog()))
			theApp.FormsManager().WriteEvent(EVENTLOG_ERROR_TYPE, MSG_TOPEX);
		ASSERT(0);
	}

	return hr;
}
*/
HRESULT  CFactory::SetFindBehaviourResponseWithin(IUnknown * pEl, short response)
{
	HRESULT hr = S_OK;
	if(response < 4)
		m_RefusalList.push_front(CPairHTMLElementAndFindBehaviourPermission(pEl,(FindBehaviourPermission)response));
	else
		hr = E_INVALIDARG;
	return hr;
	
}

HRESULT  CFactory::UnsetFindBehaviourResponseWithin(IUnknown * pEl)
{
	CListOfHTMLElementsAndFindBehaviourPermissions::iterator i = m_RefusalList.begin();
	HRESULT hr = S_FALSE;
	while(i != m_RefusalList.end())
	{
		CComPtr<IUnknown> l, r;
		i->first->QueryInterface(&l);
		pEl->QueryInterface(&r);
		
		if(l == r)
		{
			m_RefusalList.erase(i);
			hr = S_OK;
			break;
		}
		++i;
	}
	return hr;
}

STDMETHODIMP CFactory::GetDebugAgent(IXFormsDebugAgent **ppDebugAgent)
{
	HRESULT hr = CreateDebugAgentFactory();

	if(SUCCEEDED(hr))
	{
		WaitForSingleObject(sm_hDebugAgentFactoryMutex, INFINITE);

		try
		{
			hr = sm_pDebugAgentFactory->CreateInstance(0, IID_IXFormsDebugAgent, reinterpret_cast<void **>(ppDebugAgent));
		}
		catch(...)
		{
		}

		ReleaseMutex(sm_hDebugAgentFactoryMutex);
	}

	return hr;
}

STDMETHODIMP CFactory::Load( 
        /* [in] */ IPropertyBag *pPropBag,
		/* [in] */ IErrorLog *pErrorLog)
{
	HRESULT hr = E_POINTER;
	if(pPropBag)
	{
		if(m_lFormId)
		{
			hr = E_UNEXPECTED;
		}
		else
		{
			CComVariant var(0l);
			const CComBSTR sPropName(L"formKey");
			hr = pPropBag->Read(sPropName,&var,pErrorLog);
			if(E_INVALIDARG== hr)
			{
				//doesn't matter, we don't need the property
				hr = S_OK;
			}
			else if(VT_I4 == var.vt)
			{
				m_lFormId = var.lVal;
				hr = S_OK;
			}
		}
	}
	return hr;
}

STDMETHODIMP CFactory::get_EnableEventNotification(VARIANT_BOOL *pbEnableEventNotification)
{
	HRESULT hr = S_OK;

	if(pbEnableEventNotification)
		*pbEnableEventNotification = (theApp.FormsManager().AreEventNotificationsEnabled() ? VARIANT_TRUE : VARIANT_FALSE);
	else {
		hr = FP_E_BADARG;
		SetupErrorInfo(hr, L"Factory::get_EnableEventNotification");
	}

	return hr;
}

STDMETHODIMP CFactory::put_EnableEventNotification(VARIANT_BOOL bEnableEventNotification)
{
	theApp.FormsManager().SetEventNotificationState(bEnableEventNotification == VARIANT_TRUE);

	return S_OK;
}

bool CFactory::ShouldThisFindBehaviourRequestBeRefused(IElementBehaviorSite * pSite,const BSTR bstrBehavior)
{
	bool bRefuse = false;
	if(!m_RefusalList.empty())
	{
		if(pSite)
		{
			CComPtr<IHTMLElement> pEl;
			pSite->GetElement(&pEl);
			if(pEl)
			{
				CListOfHTMLElementsAndFindBehaviourPermissions::const_iterator i = m_RefusalList.begin();
				while(i != m_RefusalList.end())
				{
					CComPtr<IHTMLElement> pRefusalEl = i->first;
					if(pRefusalEl)
					{
						VARIANT_BOOL vbContains;
						pRefusalEl->contains(pEl,&vbContains);
						if(vbContains)
						{
							if(i->second == REFUSE)
								bRefuse = true;
							else if(i->second == ACTIONS || i->second ==SELECT_CHILD)
							{
								
								CMapCComBSTRToObjectCreationFunction::iterator i1 = m_ActionObjectCreationMap.end();
								if(bstrBehavior)
									i1 = m_ActionObjectCreationMap.find(bstrBehavior);
								bRefuse = (i1 == m_ActionObjectCreationMap.end());

								if(bRefuse && (i->second == SELECT_CHILD))
								{
									if((wcscmp(g_lpwszTagItemset,bstrBehavior) == 0) || (wcscmp(g_lpwszTagItem,bstrBehavior) ==0))
										bRefuse = false;
								}

							}
							break;
						}
					}
					++i;
				}
			}
		}
	}
	return bRefuse;
}
	